/*
 * A small program that send midi events to a virtual midi port (like midi yoke)
 * that I developed to experiment with "body music"
 * (I used it to simulate a wha wha pedal for instance)
 * (The skeleton of the source used is the one from the sample shiped with wiiuse, thanks!)
 */

#include <stdio.h>
#include <stdlib.h>

#include "wiiuse.h"
#include "RtMidi.h"

/* runs or stops the application */
int running=1;
/* the midiout object used to send midi messages */
RtMidiOut *midiout;
/* the midi message */
std::vector<unsigned char> message;
/* the available wiimote axes */
enum wii_axes {ROLL, PITCH, YAW};
/* default selected axe */
int selectedAxe = PITCH;

/**
 * event callback fct for the wiiuse library
 */
void handle_event(struct wiimote_t* wm) {
	int axeValue = 0;
	/* if a button is pressed, report it */
	if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)){
		printf("A pressed, exiting...\n");
		running=0;
	}
	if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS))	printf("Not sending midi events anymore\n");
	if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS))	printf("Sending midi events\n");

	/*
	 *	Minus disables the event sending
	 */
	if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS))
		wiiuse_motion_sensing(wm, 0);

	/*
	 *	plus enables the event sending
	 */
	if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS))
		wiiuse_motion_sensing(wm, 1);

	/* Send the midi event using one axe,
       the values of pitch and roll are between -180 and 180 degrees,
	   the yaw value is betwee -26 to 26 degrees so we have to make
	   it into the midi event zone of 0-127 */
	if (WIIUSE_USING_ACC(wm)) {
		if(selectedAxe==PITCH){
			axeValue = abs((int)(wm->orient.a_pitch));
			message[2]=(axeValue*127/180);
		}else if(selectedAxe==ROLL){
			axeValue = (int)(wm->orient.a_roll);
			message[2]=(axeValue*127/180);
		}else if(selectedAxe==YAW){
			axeValue = (int)(wm->orient.yaw);
			message[2]=(axeValue*127/180);
		}
		midiout->sendMessage(&message);
		printf("sent %d \n", message[2]);
	}
}


void handle_disconnect(wiimote* wm) {
	printf("\n\n--- DISCONNECTED [wiimote id %i] ---\n", wm->unid);
}

int initMidi(int paramPort=-1)
{
	std::string portName;
	unsigned int nPorts;
	int selectedPort;

	message.push_back(0xb0);
	message.push_back(0x07);
	message.push_back(0);

	// RtMidiOut constructor
	try {
		midiout = new RtMidiOut();
	}
	catch ( RtError &error ) {
		error.printMessage();
		exit( EXIT_FAILURE );
	}

	// Check outputs.
	nPorts = midiout->getPortCount();
	printf("\nThere are %d, midi output ports available\n", nPorts);
	for ( unsigned int i=0; i<nPorts; i++ ) {
		try {
			portName = midiout->getPortName(i);
		}
		catch (RtError &error) {
			error.printMessage();
			delete midiout;
		}
		std::cout << "Output Port #" << i << portName <<"\n";
	}
	printf("\n");

	if(paramPort==-1){
		printf("Enter the number you would like to use:");
		std::cin>>selectedPort;
		midiout->openPort(selectedPort);
	}else{
		printf("Using port %d", paramPort);
		midiout->openPort(paramPort);
	}
}

int main(int argc, char** argv) {
	int port = -1;
	/* -------------------------------------------------------------------------------------*/
	/* absolutely no testing, just be careful damn it's not that compicated! */
	for(int i=1 ; i<argc ; i++){
		if(strcmp(argv[i], "p")){
			i++;
			port = atoi(argv[i]);
		}else if(strcmp(argv[i], "a")){
			i++;
			selectedAxe = atoi(argv[i]);
		}else if(strcmp(argv[i], "h")){
			printf("usage: widi -p <midi output port> -a <wiimote axe> (0:ROLL, 1:PITCH, 2:YAW)\n");
			return 0;
		}
	}
	
	/* -------------------------------------------------------------------------------------*/
	/*wii init part*/
	wiimote** wiimotes;
	int found, connected;

	wiimotes =  wiiuse_init(1);

	wiiuse_set_bluetooth_stack(wiimotes, 1, WIIUSE_STACK_MS); 

	found = wiiuse_find(wiimotes, 1, 5);
	if (!found) {
		printf ("No wiimotes found.");
		std::cin>>found;
		return 0;
	}

	connected = wiiuse_connect(wiimotes, 1);
	if (connected)
		printf("Connected to %i wiimotes (of %i found).\n", connected, found);
	else {
		printf("Failed to connect to any wiimote.\n");
		return 0;
	}

	wiiuse_set_leds(wiimotes[0], WIIMOTE_LED_1);


	/* -------------------------------------------------------------------------------------*/
	/* init miid part */
	initMidi(port);
	

	/* -------------------------------------------------------------------------------------*/
	/* main loop */
	while (running==1) {
		if (wiiuse_poll(wiimotes, 1)) {
			int i = 0;
			switch (wiimotes[i]->event) {
				case WIIUSE_EVENT:
					/* a generic event occured */
					handle_event(wiimotes[i]);
					break;

				case WIIUSE_DISCONNECT:
				case WIIUSE_UNEXPECTED_DISCONNECT:
					/* the wiimote disconnected */
					handle_disconnect(wiimotes[i]);
					break;

				default:
					break;
			}
		}
	}

	/* -------------------------------------------------------------------------------------*/
	/* owari! */
	wiiuse_cleanup(wiimotes, 1);
	delete midiout;

	return 0;
}
